package cn.itcast.n4_共享模型_管程;

import lombok.extern.slf4j.Slf4j;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

import static cn.itcast.util.Sleeper.sleep;

/**
 * @program: juc
 * @description:
 * @author: flyduck
 * @create: 2024-10-08 16:54
 **/
@Slf4j(topic = "c.Test31_$$$$$_wait_notify设计模式_一个线程等待另外一个线程执行结果_保护性暂停_多个线程等待多个线程的结果")
public class Test31_$$$$$_wait_notify设计模式_一个线程等待另外一个线程执行结果_保护性暂停_多个线程等待多个线程的结果 {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new People().start();
        }
        sleep(1);

        for (Integer id : MailBox.getIds()) {
            new Postman(id,"内容" + id).start();
        }

    }
}

@Slf4j(topic = "c.People")
class People extends Thread{

    @Override
    public void run() {
        //收信
        //必须先有盒子
        GuardedObject3 guardedObject3 = new GuardedObject3(IdUtils.generateId());
        MailBox.addGuardedObject(guardedObject3);

        log.debug("开始收信，信id:{}", guardedObject3.getId());
        Object mail = guardedObject3.getResult(5000);
        log.debug("收到信了，信id:{}，信件内容：{}", guardedObject3.getId(),mail);

    }
}

@Slf4j(topic = "c.Postman")
class Postman extends Thread{

    private Integer id;
    private String mail;

    public Postman(Integer id, String mail) {
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
        //寄信
        GuardedObject3 guardedObject3 = MailBox.deleteGuardedObjectById(id);
        log.debug("开始送信，信id:{}，邮件内容:{}", guardedObject3.getId(),mail);
        guardedObject3.setResult(mail);
    }
}

class MailBox{
    private static Map<Integer,GuardedObject3> guardedObject3Map = new Hashtable<>();

    public static void addGuardedObject(GuardedObject3 guardedObject3){
        guardedObject3Map.put(guardedObject3.getId(), guardedObject3);
    }

    public static Set<Integer> getIds(){
        return guardedObject3Map.keySet();
    }

    public static GuardedObject3 deleteGuardedObjectById(Integer id){
        return guardedObject3Map.remove(id);
    }
}

class GuardedObject3 {
    private int id;//唯一标识
    private Object result;//等待的结果

    public GuardedObject3(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public Object getResult(long timeout) {
        synchronized (this) {
            long beginTime = System.currentTimeMillis();
            while (result == null) {
                long passTime = System.currentTimeMillis() - beginTime;//经历的时间
                long waitTime = timeout - passTime;//需要等待的时间
                if(waitTime <= 0){//如果需要等待的时间<=0，就返回
                    break;
                }
                try {
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    }

//    public Object getResult(long timeout) {
//        synchronized (this) {
//            while (result == null) {
//                try {
//                    //问题1：比如timeout=2000,如果直接这样写，在1000后被打断了以后，下次进来会再次等待2000
//                    //问题2：等待2000后，他会继续循环
//                    this.wait(timeout);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//            return result;
//        }
//    }

    public Object getResult() {
        synchronized (this) {
            while (result == null) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    }

    public void setResult(Object result) {
        synchronized (this) {
            this.result = result;
            this.notifyAll();
        }
    }
}

class IdUtils{
    private static int id = 1;

    public static synchronized int generateId(){
        return id++;
    }
}
